package com.t.bricks.bussiness.component.lucene;

import java.util.List;
import java.util.Map;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.t.bricks.bussiness.db.dao.common.CommonDao;
import com.t.bricks.bussiness.util.lucene.LuceneFactory;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.model.OrderInfoList;
import com.t.bricks.utils.function.reflect.ReflectUtil;
import com.t.bricks.utils.spring.ModuleUtil;
import com.t.bricks.utils.spring.SpringContextUtil;

/**
 * 搜索引擎切面子类,专门处理更新数据时的关联操作
 */
@Component
@Aspect
public class LuceneAspectEdit extends LuceneAspectBase {

	@Autowired
	private CommonDao commonDao;
	
	/**
	 * 定义切入点，切入点为'MsgEmity com.t.bricks.bussiness.db.dao.*.impl.*DaoImpl.edit(?)'下的del函数,并且函数只有一个参数
	 */
	@Pointcut(value = "execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.edit(..))")
	//@Pointcut(value = "execution(* com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.*(..))")
	@Override
	public void doLuceneAspect() {
	}
    
	/**
	 * 后置/返回值增强
     * @param joinPoint
     * @param result 被切点方法执行后的返回值
     * @return
	 */
	@AfterReturning(returning="result", pointcut="doLuceneAspect()")
	public void afterReturning(JoinPoint joinPoint, Object result) {
		if (!isCanAop) {
			return;//不进行搜索引擎切面操作,退出
		}
		
		if (!(result instanceof MsgEmity)) {//不是返回MsgEmity,则说明已经改变
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			String methodName = signature.getMethod().getName();
			Log.error("方法'", methodName, "'返回数据不是MsgEmity");
			return;
		}
		
		MsgEmity msgEmity = (MsgEmity)result;
		if (!msgEmity.isSuccess()) {
			return;//原方法执行失败,不处理
		}
		
		edit(joinPoint, msgEmity);//多线程处理
	}

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
	@Around("doLuceneAspect()")
	@Override
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		return joinPoint.proceed();//执行原切面中的预定方法后返回内容
	}

	/**
	 * 更新数据
	 * 注意:lucene的update比较特殊，update的代价太高，其实是先删除，然后在插入
	 * @param joinPoint
	 * @param msgEmity
	 */
	private void edit(JoinPoint joinPoint, MsgEmity msgEmity) {
		ModuleUtil.runThread(() -> {//多线程方式重新构造缓存数据
			Object entity = msgEmity.getData();//执行了DAO的add方法后,返回的实体对象
			JoinPoint FjoinPoint = joinPoint;
		
			crateLuceneCore(FjoinPoint, sLuceneIndexPath);//建立搜索库,不论是否成功都往下走
			
			Map<String, String> map = getKeyInfo(entity);
			if (map == null) {
				Log.error("无法获取", entity.getClass().getSimpleName(), "修改后的id值,请检查数据库的主键名称是否符合,同时脚本语句是否获取了新数据对应的id!");
				return;
			}
			
			String idName = map.get("idName");
			String idObj = map.get("idObj");
			
			Class<?> clazz = getGenericClass(msgEmity);
			String whereStr = new StringBuilder()//表名前不能加"[dbo]."，否则sql会报错
				.append(clazz.getSimpleName())
				.append(".").append(idName).append(" = ")
				.append(("sId".equals(idName) || "uId".equals(idName)) ? "'" : "")
				.append(idObj)
				.append(("sId".equals(idName) || "uId".equals(idName)) ? "'" : "")
				.toString();
			
			String beanName = getDaoBeanName(joinPoint);
			
			MsgEmity me = null;
			
			Object bean = SpringContextUtil.getBean(beanName);
			if (ReflectUtil.hasMethod("findBySearch", bean, String.class, OrderInfoList.class, Class.class)) {
				me = SpringContextUtil.doMethod(
						beanName, "findBySearch",
						new Class<?>[]{ String.class, OrderInfoList.class, Class.class },
						new Object[]{ whereStr, null, entity.getClass() });
			} else {
				me = SpringContextUtil.doMethod(
						beanName, "findBySearch",
						new Class<?>[]{ String.class, OrderInfoList.class },
						new Object[]{ whereStr, null });
			}
			
			if (null == me || !me.isSuccess()) {
				Log.error("搜索引擎读取数据失败!");
				return;
			}
			
			me = me.getData();//SpringContextUtil.doMethod返回的data里面是MsgEmity
			if (!me.isSuccess()) {
				Log.error("Dao'", beanName, "'读取数据失败!");
				return;
			}
			
			List<?> list = me.getData();
			if (list.size() < 1) {
				return;
			}
			
			LuceneFactory.update(idName, idObj, list.get(0), getCore(joinPoint, sLuceneIndexPath));
		});
	}

	/**
	 * 定义切入点，切入点为'MsgEmity com.t.bricks.bussiness.db.dao.*.impl.*DaoImpl.edit(?)'下的del函数,并且函数只有一个参数
	 */
	@Pointcut(value = "execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeValues(Class, Object, *, Integer, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeValueById(Class, Object, String, Object, Integer, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeValue(Class, *, String, Object, Integer, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeNumber(Class, Object, Integer, String, Object, boolean, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.subNumber(Class, Object, Integer, String, Object, boolean, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.incNumber(Class, Object, Integer, String, Object, boolean, boolean))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeState(Object, Integer, Integer, String, Class))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.changeSetp(Object, Integer, Integer, String, boolean, Class))")
	//@Pointcut(value = "execution(* com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.*(..))")
	public void commonDaoAspect() {
	}
    
	/**
	 * 后置/返回值增强
     * @param joinPoint
     * @param result 被切点方法执行后的返回值
     * @return
	 */
	@AfterReturning(returning="result", pointcut="commonDaoAspect()")
	public void afterReturningByCommonDao(JoinPoint joinPoint, Object result) {
		if (!isCanAop) {
			return;//不进行搜索引擎切面操作,退出
		}
		
		if (!(result instanceof MsgEmity)) {//不是返回MsgEmity,则说明已经改变
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			String methodName = signature.getMethod().getName();
			Log.error("方法'", methodName, "'返回数据不是MsgEmity");
			return;
		}
		
		MsgEmity msgEmity = (MsgEmity)result;
		if (!msgEmity.isSuccess()) {
			return;//原方法执行失败,不处理
		}
		
		editByCommonDao(joinPoint);//多线程处理
	}
	
	/**
	 * 更新数据
	 * 注意:lucene的update比较特殊，update的代价太高，其实是先删除，然后在插入
	 * @param joinPoint
	 * @param msgEmity
	 */
	private void editByCommonDao(JoinPoint joinPoint) {
		ModuleUtil.runThread(() -> {//多线程方式重新构造缓存数据
			crateLuceneCore(joinPoint, sLuceneIndexPath);//建立搜索库,不论是否成功都往下走
			
			Object[] objs = joinPoint.getArgs();
			String sMonthName = joinPoint.getSignature().getName();
			
			Class<?> entityClass = null;
			Object idValue = null;
			
			if ("changeValues".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				idValue = objs[1];
			}
			
			if ("changeValueById".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				idValue = objs[1];
			}
			
			if ("changeValue".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				@SuppressWarnings("unchecked")
				Map<String, Object> whereMap = (Map<String, Object>)objs[1];

				MsgEmity me = commonDao.findByMapToSearch(whereMap, entityClass);
				if (!me.isSuccess()) {
					return;
				}

				String idName = getIdName(entityClass);
				String core = getCore(joinPoint, sLuceneIndexPath);
				List<Map<String, Object>> list = me.getData();
				for (Map<String, Object> map : list) {
					LuceneFactory.update(idName, String.valueOf(map.get(idName)), map, core);
				}

				return;
			}
			
			if ("changeNumber".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				idValue = objs[1];
			}
			
			if ("subNumber".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				idValue = objs[1];
			}
			
			if ("incNumber".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[0];
				idValue = objs[1];
			}
			
			if ("changeState".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[4];
				idValue = objs[0];
			}
			
			if ("changeSetp".equalsIgnoreCase(sMonthName)) {
				entityClass = (Class<?>)objs[5];
				idValue = objs[0];
			}

			MsgEmity me = commonDao.findByPageRow(idValue, entityClass);
			if (!me.isSuccess()) {
				return;
			}
			
			String idName = getIdName(entityClass);

			LuceneFactory.update(idName, String.valueOf(idValue), me.getData(), getCore(joinPoint, sLuceneIndexPath));
		});
	}

}
